home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / MOR55SRC.ZIP / MORIA / SOURCE / DESC.C < prev    next >
C/C++ Source or Header  |  1992-12-07  |  18KB  |  748 lines

  1. /* source/desc.c: handle object descriptions, mostly string handling code
  2.  
  3.    Copyright (c) 1989-92 James E. Wilson, Robert A. Koeneke
  4.  
  5.    This software may be copied and distributed for educational, research, and
  6.    not for profit purposes provided that this copyright and statement are
  7.    included in all such copies. */
  8.  
  9. #ifdef __TURBOC__
  10. #include    <stdio.h>
  11. #include    <stdlib.h>
  12. #endif /* __TURBOC__ */
  13.  
  14. #include "config.h"
  15. #include "constant.h"
  16. #include "types.h"
  17. #include "externs.h"
  18.  
  19. #ifdef USG
  20. #ifndef ATARIST_MWC
  21. #include <string.h>
  22. #endif
  23. #else
  24. #include <strings.h>
  25. #endif
  26.  
  27. #if defined(LINT_ARGS)
  28. static void unsample(struct inven_type *);
  29. #else
  30. static void unsample();
  31. #endif
  32.  
  33. #ifdef ATARIST_TC
  34. /* Include this to get prototypes for standard library functions.  */
  35. #include <stdlib.h>
  36. #endif
  37.  
  38. char titles[MAX_TITLES][10];
  39.  
  40. /* Object descriptor routines                    */
  41.  
  42. int is_a_vowel(ch)
  43. char ch;
  44. {
  45.   switch(ch)
  46.     {
  47.     case 'a': case 'e': case 'i': case 'o': case 'u':
  48.     case 'A': case 'E': case 'I': case 'O': case 'U':
  49.       return(TRUE);
  50.     default:
  51.       return(FALSE);
  52.     }
  53. }
  54.  
  55. /* Initialize all Potions, wands, staves, scrolls, etc.    */
  56. void magic_init()
  57. {
  58.   register int h, i, j, k;
  59.   register char *tmp;
  60.   vtype string;
  61.  
  62.   set_seed(randes_seed);
  63.  
  64.   /* The first 3 entries for colors are fixed, (slime & apple juice, water) */
  65.   for (i = 3; i < MAX_COLORS; i++)
  66.     {
  67.       j = randint(MAX_COLORS - 3) + 2;
  68.       tmp = colors[i];
  69.       colors[i] = colors[j];
  70.       colors[j] = tmp;
  71.     }
  72.   for (i = 0; i < MAX_WOODS; i++)
  73.     {
  74.       j = randint(MAX_WOODS) - 1;
  75.       tmp = woods[i];
  76.       woods[i] = woods[j];
  77.       woods[j] = tmp;
  78.     }
  79.   for (i = 0; i < MAX_METALS; i++)
  80.     {
  81.       j = randint(MAX_METALS) - 1;
  82.       tmp = metals[i];
  83.       metals[i] = metals[j];
  84.       metals[j] = tmp;
  85.     }
  86.   for (i = 0; i < MAX_ROCKS; i++)
  87.     {
  88.       j = randint(MAX_ROCKS) - 1;
  89.       tmp = rocks[i];
  90.       rocks[i] = rocks[j];
  91.       rocks[j] = tmp;
  92.     }
  93.   for (i = 0; i < MAX_AMULETS; i++)
  94.     {
  95.       j = randint(MAX_AMULETS) - 1;
  96.       tmp = amulets[i];
  97.       amulets[i] = amulets[j];
  98.       amulets[j] = tmp;
  99.     }
  100.   for (i = 0; i < MAX_MUSH; i++)
  101.     {
  102.       j = randint(MAX_MUSH) - 1;
  103.       tmp = mushrooms[i];
  104.       mushrooms[i] = mushrooms[j];
  105.       mushrooms[j] = tmp;
  106.     }
  107.   for (h = 0; h < MAX_TITLES; h++)
  108.     {
  109.       string[0] = '\0';
  110.       k = randint(2) + 1;
  111.       for (i = 0; i < k; i++)
  112.     {
  113.       for (j = randint(2); j > 0; j--)
  114.         (void) strcat(string, syllables[randint(MAX_SYLLABLES) - 1]);
  115.       if (i < k-1)
  116.         (void) strcat(string, " ");
  117.     }
  118.       if (string[8] == ' ')
  119.     string[8] = '\0';
  120.       else
  121.     string[9] = '\0';
  122.       (void) strcpy(titles[h], string);
  123.     }
  124.   reset_seed();
  125. }
  126.  
  127. int16 object_offset(t_ptr)
  128. inven_type *t_ptr;
  129. {
  130.   switch (t_ptr->tval)
  131.     {
  132.     case TV_AMULET:    return(0);
  133.     case TV_RING:    return(1);
  134.     case TV_STAFF:    return(2);
  135.     case TV_WAND:    return(3);
  136.     case TV_SCROLL1:
  137.     case TV_SCROLL2:    return(4);
  138.     case TV_POTION1:
  139.     case TV_POTION2:    return(5);
  140.     case TV_FOOD:
  141.       if ((t_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1)) < MAX_MUSH)
  142.     return(6);
  143.       return(-1);
  144.     default:  return(-1);
  145.     }
  146. }
  147.  
  148. /* Remove "Secret" symbol for identity of object            */
  149. void known1(i_ptr)
  150. inven_type *i_ptr;
  151. {
  152.   int16 offset;
  153.   int8u indexx;
  154.  
  155.   if ((offset = object_offset(i_ptr)) < 0)
  156.     return;
  157.   offset <<= 6;
  158.   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
  159.   object_ident[offset + indexx] |= OD_KNOWN1;
  160.   /* clear the tried flag, since it is now known */
  161.   object_ident[offset + indexx] &= ~OD_TRIED;
  162. }
  163.  
  164. int known1_p(i_ptr)
  165. inven_type *i_ptr;
  166. {
  167.   int16 offset;
  168.   int8u indexx;
  169.  
  170.   /* Items which don't have a 'color' are always known1, so that they can
  171.      be carried in order in the inventory.  */
  172.   if ((offset = object_offset(i_ptr)) < 0)
  173.     return OD_KNOWN1;
  174.   if (store_bought_p(i_ptr))
  175.     return OD_KNOWN1;
  176.   offset <<= 6;
  177.   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
  178.   return(object_ident[offset + indexx] & OD_KNOWN1);
  179. }
  180.  
  181. /* Remove "Secret" symbol for identity of plusses            */
  182. void known2(i_ptr)
  183. inven_type *i_ptr;
  184. {
  185.   unsample(i_ptr);
  186.   i_ptr->ident |= ID_KNOWN2;
  187. }
  188.  
  189. int known2_p(i_ptr)
  190. inven_type *i_ptr;
  191. {
  192.   return (i_ptr->ident & ID_KNOWN2);
  193. }
  194.  
  195. void clear_known2(i_ptr)
  196. inven_type *i_ptr;
  197. {
  198.   i_ptr->ident &= ~ID_KNOWN2;
  199. }
  200.  
  201. void clear_empty(i_ptr)
  202. inven_type *i_ptr;
  203. {
  204.   i_ptr->ident &= ~ID_EMPTY;
  205. }
  206.  
  207. void store_bought(i_ptr)
  208. inven_type *i_ptr;
  209. {
  210.   i_ptr->ident |= ID_STOREBOUGHT;
  211.   known2(i_ptr);
  212. }
  213.  
  214. int store_bought_p(i_ptr)
  215. inven_type *i_ptr;
  216. {
  217.   return (i_ptr->ident & ID_STOREBOUGHT);
  218. }
  219.  
  220. /*    Remove an automatically generated inscription.    -CJS- */
  221. static void unsample(i_ptr)
  222. inven_type *i_ptr;
  223. {
  224.   int16 offset;
  225.   int8u indexx;
  226.  
  227.   /* used to clear ID_DAMD flag, but I think it should remain set */
  228.   i_ptr->ident &= ~(ID_MAGIK|ID_EMPTY);
  229.   if ((offset = object_offset(i_ptr)) < 0)
  230.     return;
  231.   offset <<= 6;
  232.   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
  233.   object_ident[offset + indexx] &= ~OD_TRIED;
  234. }
  235.  
  236. /* unquote() is no longer needed */
  237.  
  238. /* Somethings been sampled -CJS- */
  239. void sample (i_ptr)
  240. inven_type *i_ptr;
  241. {
  242.   int16 offset;
  243.   int8u indexx;
  244.  
  245.   if ((offset = object_offset(i_ptr)) < 0)
  246.     return;
  247.   offset <<= 6;
  248.   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
  249.   object_ident[offset + indexx] |= OD_TRIED;
  250. }
  251.  
  252. /* Somethings been identified                    */
  253. /* extra complexity by CJS so that it can merge store/dungeon objects
  254.    when appropriate */
  255. void identify(item)
  256. int *item;
  257. {
  258.   register int i, x1, x2;
  259.   int j;
  260.   register inven_type *i_ptr, *t_ptr;
  261. #ifdef ATARIST_MWC
  262.   int32u holder;
  263. #endif
  264.  
  265.   i_ptr = &inventory[*item];
  266.  
  267. #ifdef ATARIST_MWC
  268.   if (i_ptr->flags & (holder = TR_CURSED))
  269. #else
  270.   if (i_ptr->flags & TR_CURSED)
  271. #endif
  272.     add_inscribe(i_ptr, ID_DAMD);
  273.  
  274.   if (!known1_p(i_ptr))
  275.     {
  276.       known1(i_ptr);
  277.       x1 = i_ptr->tval;
  278.       x2 = i_ptr->subval;
  279.       if (x2 < ITEM_SINGLE_STACK_MIN || x2 >= ITEM_GROUP_MIN)
  280.     /* no merging possible */
  281.     ;
  282.       else
  283.     for (i = 0; i < inven_ctr; i++)
  284.       {
  285.         t_ptr = &inventory[i];
  286.         if (t_ptr->tval == x1 && t_ptr->subval == x2 && i != *item
  287.         && ((int)t_ptr->number + (int)i_ptr->number < 256))
  288.           {
  289.         /* make *item the smaller number */
  290.         if (*item > i)
  291.           {
  292.             j = *item; *item = i; i = j;
  293.           }
  294.       msg_print ("You combine similar objects from the shop and dungeon.");
  295.  
  296.         inventory[*item].number += inventory[i].number;
  297.         inven_ctr--;
  298.         for (j = i; j < inven_ctr; j++)
  299.           inventory[j] = inventory[j+1];
  300.         invcopy(&inventory[j], OBJ_NOTHING);
  301.           }
  302.       }
  303.     }
  304. }
  305.  
  306. /* If an object has lost magical properties,
  307.  * remove the appropriate portion of the name.           -CJS-
  308.  */
  309. void unmagic_name(i_ptr)
  310. inven_type *i_ptr;
  311. {
  312.   i_ptr->name2 = SN_NULL;
  313. }
  314.  
  315. /* defines for p1_use, determine how the p1 field is printed */
  316. #define IGNORED  0
  317. #define CHARGES  1
  318. #define PLUSSES  2
  319. #define LIGHT    3
  320. #define FLAGS    4
  321. #define Z_PLUSSES 5
  322.  
  323. /* Returns a description of item for inventory            */
  324. /* pref indicates that there should be an article added (prefix) */
  325. /* note that since out_val can easily exceed 80 characters, objdes must
  326.    always be called with a bigvtype as the first paramter */
  327. void objdes(out_val, i_ptr, pref)
  328. char *out_val;
  329. register inven_type *i_ptr;
  330. int pref;
  331. {
  332.   /* base name, modifier string*/
  333.   register char *basenm, *modstr;
  334.   bigvtype tmp_val;
  335.   vtype tmp_str, damstr;
  336.   int indexx, p1_use, modify, append_name, tmp;
  337.  
  338.   indexx = i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1);
  339.   basenm = object_list[i_ptr->index].name;
  340.   modstr = CNIL;
  341.   damstr[0] = '\0';
  342.   p1_use = IGNORED;
  343.   modify = (known1_p(i_ptr) ? FALSE : TRUE);
  344.   append_name = FALSE;
  345.   switch(i_ptr->tval)
  346.     {
  347.     case  TV_MISC:
  348.     case  TV_CHEST:
  349.       break;
  350.     case  TV_SLING_AMMO:
  351.     case  TV_BOLT:
  352.     case  TV_ARROW:
  353.       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
  354.       break;
  355.     case  TV_LIGHT:
  356.       p1_use = LIGHT;
  357.       break;
  358.     case  TV_SPIKE:
  359.       break;
  360.     case  TV_BOW:
  361.       if (i_ptr->p1 == 1 || i_ptr->p1 == 2)
  362.     tmp = 2;
  363.       else if (i_ptr->p1 == 3 || i_ptr->p1 == 5)
  364.     tmp = 3;
  365.       else if (i_ptr->p1 == 4 || i_ptr->p1 == 6)
  366.     tmp = 4;
  367.       else
  368.     tmp = -1;
  369.       (void) sprintf (damstr, " (x%d)", tmp);
  370.       break;
  371.     case  TV_HAFTED:
  372.     case  TV_POLEARM:
  373.     case  TV_SWORD:
  374.       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
  375.       p1_use = FLAGS;
  376.       break;
  377.     case  TV_DIGGING:
  378.       p1_use = Z_PLUSSES;
  379.       (void) sprintf(damstr, " (%dd%d)", i_ptr->damage[0], i_ptr->damage[1]);
  380.       break;
  381.     case  TV_BOOTS:
  382.     case  TV_GLOVES:
  383.     case  TV_CLOAK:
  384.     case  TV_HELM:
  385.     case  TV_SHIELD:
  386.     case  TV_HARD_ARMOR:
  387.     case  TV_SOFT_ARMOR:
  388.       break;
  389.     case  TV_AMULET:
  390.       if (modify)
  391.     {
  392.       basenm = "& %s Amulet";
  393.       modstr = amulets[indexx];
  394.     }
  395.       else
  396.     {
  397.       basenm = "& Amulet";
  398.       append_name = TRUE;
  399.     }
  400.       p1_use = PLUSSES;
  401.       break;
  402.     case  TV_RING:
  403.       if (modify)
  404.     {
  405.       basenm = "& %s Ring";
  406.       modstr = rocks[indexx];
  407.     }
  408.       else
  409.     {
  410.       basenm = "& Ring";
  411.       append_name = TRUE;
  412.     }
  413.       p1_use = PLUSSES;
  414.       break;
  415.     case  TV_STAFF:
  416.       if (modify)
  417.     {
  418.       basenm = "& %s Staff";
  419.       modstr = woods[indexx];
  420.     }
  421.       else
  422.     {
  423.       basenm = "& Staff";
  424.       append_name = TRUE;
  425.     }
  426.       p1_use = CHARGES;
  427.       break;
  428.     case  TV_WAND:
  429.       if (modify)
  430.     {
  431.       basenm = "& %s Wand";
  432.       modstr = metals[indexx];
  433.     }
  434.       else
  435.     {
  436.       basenm = "& Wand";
  437.       append_name = TRUE;
  438.     }
  439.       p1_use = CHARGES;
  440.       break;
  441.     case  TV_SCROLL1:
  442.     case  TV_SCROLL2:
  443.       if (modify)
  444.     {
  445.       basenm =  "& Scroll~ titled \"%s\"";
  446.       modstr = titles[indexx];
  447.     }
  448.       else
  449.     {
  450.       basenm = "& Scroll~";
  451.       append_name = TRUE;
  452.     }
  453.       break;
  454.     case  TV_POTION1:
  455.     case  TV_POTION2:
  456.       if (modify)
  457.     {
  458.       basenm = "& %s Potion~";
  459.       modstr = colors[indexx];
  460.     }
  461.       else
  462.     {
  463.       basenm = "& Potion~";
  464.       append_name = TRUE;
  465.     }
  466.       break;
  467.     case  TV_FLASK:
  468.       break;
  469.     case  TV_FOOD:
  470.       if (modify)
  471.     {
  472.       if (indexx <= 15)
  473.         basenm = "& %s Mushroom~";
  474.       else if (indexx <= 20)
  475.         basenm = "& Hairy %s Mold~";
  476.       if (indexx <= 20)
  477.         modstr = mushrooms[indexx];
  478.     }
  479.       else
  480.     {
  481.       append_name = TRUE;
  482.       if (indexx <= 15)
  483.         basenm = "& Mushroom~";
  484.       else if (indexx <= 20)
  485.         basenm = "& Hairy Mold~";
  486.       else
  487.         /* Ordinary food does not have a name appended.  */
  488.         append_name = FALSE;
  489.     }
  490.       break;
  491.     case  TV_MAGIC_BOOK:
  492.       modstr = basenm;
  493.       basenm = "& Book~ of Magic Spells %s";
  494.       break;
  495.     case  TV_PRAYER_BOOK:
  496.       modstr = basenm;
  497.       basenm = "& Holy Book~ of Prayers %s";
  498.       break;
  499.     case TV_OPEN_DOOR:
  500.     case TV_CLOSED_DOOR:
  501.     case TV_SECRET_DOOR:
  502.     case TV_RUBBLE:
  503.       break;
  504.     case TV_GOLD:
  505.     case TV_INVIS_TRAP:
  506.     case TV_VIS_TRAP:
  507.     case TV_UP_STAIR:
  508.     case TV_DOWN_STAIR:
  509.       (void) strcpy(out_val, object_list[i_ptr->index].name);
  510.       (void) strcat(out_val, ".");
  511.       return;
  512.     case TV_STORE_DOOR:
  513.       (void) sprintf(out_val, "the entrance to the %s.",
  514.              object_list[i_ptr->index].name);
  515.       return;
  516.     default:
  517.       (void) strcpy(out_val, "Error in objdes()");
  518.       return;
  519.     }
  520.   if (modstr != CNIL)
  521.     (void) sprintf(tmp_val, basenm, modstr);
  522.   else
  523.     (void) strcpy(tmp_val, basenm);
  524.   if (append_name)
  525.     {
  526.       (void) strcat(tmp_val, " of ");
  527.       (void) strcat(tmp_val, object_list[i_ptr->index].name);
  528.     }
  529.   if (i_ptr->number != 1)
  530.     {
  531.       insert_str(tmp_val, "ch~", "ches");
  532.       insert_str(tmp_val, "~", "s");
  533.     }
  534.   else
  535.     insert_str(tmp_val, "~", CNIL);
  536.   if (!pref)
  537.     {
  538.       if (!strncmp("some", tmp_val, 4))
  539.     (void) strcpy(out_val, &tmp_val[5]);
  540.       else if (tmp_val[0] == '&')
  541.     /* eliminate the '& ' at the beginning */
  542.     (void) strcpy(out_val, &tmp_val[2]);
  543.       else
  544.     (void) strcpy(out_val, tmp_val);
  545.     }
  546.   else
  547.     {
  548.       if (i_ptr->name2 != SN_NULL && known2_p(i_ptr))
  549.     {
  550.       (void) strcat(tmp_val, " ");
  551.       (void) strcat(tmp_val, special_names[i_ptr->name2]);
  552.     }
  553.       if (damstr[0] != '\0')
  554.     (void) strcat(tmp_val, damstr);
  555.       if (known2_p(i_ptr))
  556.     {
  557.       /* originally used %+d, but several machines don't support it */
  558.       if (i_ptr->ident & ID_SHOW_HITDAM)
  559.         (void) sprintf(tmp_str, " (%c%d,%c%d)",
  560.                (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit),
  561.                (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam));
  562.       else if (i_ptr->tohit != 0)
  563.         (void) sprintf(tmp_str, " (%c%d)",
  564.                (i_ptr->tohit < 0) ? '-' : '+', abs(i_ptr->tohit));
  565.       else if (i_ptr->todam != 0)
  566.         (void) sprintf(tmp_str, " (%c%d)",
  567.                (i_ptr->todam < 0) ? '-' : '+', abs(i_ptr->todam));
  568.       else
  569.         tmp_str[0] = '\0';
  570.       (void) strcat(tmp_val, tmp_str);
  571.     }
  572.       /* Crowns have a zero base AC, so make a special test for them. */
  573.       if (i_ptr->ac != 0 || (i_ptr->tval == TV_HELM))
  574.     {
  575.       (void) sprintf(tmp_str, " [%d", i_ptr->ac);
  576.       (void) strcat(tmp_val, tmp_str);
  577.       if (known2_p(i_ptr))
  578.         {
  579.           /* originally used %+d, but several machines don't support it */
  580.           (void) sprintf(tmp_str, ",%c%d",
  581.                  (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac));
  582.           (void) strcat(tmp_val, tmp_str);
  583.         }
  584.       (void) strcat(tmp_val, "]");
  585.     }
  586.       else if ((i_ptr->toac != 0) && known2_p(i_ptr))
  587.     {
  588.       /* originally used %+d, but several machines don't support it */
  589.       (void) sprintf(tmp_str, " [%c%d]",
  590.              (i_ptr->toac < 0) ? '-' : '+', abs(i_ptr->toac));
  591.       (void) strcat(tmp_val, tmp_str);
  592.     }
  593.  
  594.       /* override defaults, check for p1 flags in the ident field */
  595.       if (i_ptr->ident & ID_NOSHOW_P1)
  596.     p1_use = IGNORED;
  597.       else if (i_ptr->ident & ID_SHOW_P1)
  598.     p1_use = Z_PLUSSES;
  599.       tmp_str[0] = '\0';
  600.       if (p1_use == LIGHT)
  601.     (void) sprintf(tmp_str, " with %d turns of light", i_ptr->p1);
  602.       else if (p1_use == IGNORED)
  603.     ;
  604.       else if (known2_p(i_ptr))
  605.     {
  606.       if (p1_use == Z_PLUSSES)
  607.       /* originally used %+d, but several machines don't support it */
  608.         (void) sprintf(tmp_str, " (%c%d)",
  609.                (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1));
  610.       else if (p1_use == CHARGES)
  611.         (void) sprintf(tmp_str, " (%d charges)", i_ptr->p1);
  612.       else if (i_ptr->p1 != 0)
  613.         {
  614.           if (p1_use == PLUSSES)
  615.             (void) sprintf(tmp_str, " (%c%d)",
  616.                    (i_ptr->p1 < 0) ? '-' : '+', abs(i_ptr->p1));
  617.           else if (p1_use == FLAGS)
  618.         {
  619.           if (i_ptr->flags & TR_STR)
  620.             (void) sprintf(tmp_str, " (%c%d to STR)",
  621.                    (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1));
  622.           else if (i_ptr->flags & TR_STEALTH)
  623.             (void) sprintf(tmp_str, " (%c%d to stealth)",
  624.                    (i_ptr->p1 < 0) ? '-' : '+',abs(i_ptr->p1));
  625.         }
  626.         }
  627.     }
  628.       (void) strcat(tmp_val, tmp_str);
  629.  
  630.       /* ampersand is always the first character */
  631.       if (tmp_val[0] == '&')
  632.     {
  633.       /* use &tmp_val[1], so that & does not appear in output */
  634.       if (i_ptr->number > 1)
  635.         (void) sprintf(out_val, "%d%s", (int)i_ptr->number, &tmp_val[1]);
  636.       else if (i_ptr->number < 1)
  637.         (void) sprintf(out_val, "%s%s", "no more", &tmp_val[1]);
  638.       else if (is_a_vowel(tmp_val[2]))
  639.         (void) sprintf(out_val, "an%s", &tmp_val[1]);
  640.       else
  641.         (void) sprintf(out_val, "a%s", &tmp_val[1]);
  642.     }
  643.       /* handle 'no more' case specially */
  644.       else if (i_ptr->number < 1)
  645.     {
  646.       /* check for "some" at start */
  647.       if (!strncmp("some", tmp_val, 4))
  648.         (void) sprintf(out_val, "no more %s", &tmp_val[5]);
  649.       /* here if no article */
  650.       else
  651.         (void) sprintf(out_val, "no more %s", tmp_val);
  652.     }
  653.       else
  654.     (void) strcpy(out_val, tmp_val);
  655.  
  656.       tmp_str[0] = '\0';
  657.       if ((indexx = object_offset(i_ptr)) >= 0)
  658.     {
  659.       indexx = (indexx <<= 6) +
  660.         (i_ptr->subval & (ITEM_SINGLE_STACK_MIN - 1));
  661.       /* don't print tried string for store bought items */
  662.       if ((object_ident[indexx] & OD_TRIED) && !store_bought_p(i_ptr))
  663.         (void) strcat(tmp_str, "tried ");
  664.     }
  665.       if (i_ptr->ident & (ID_MAGIK|ID_EMPTY|ID_DAMD))
  666.     {
  667.       if (i_ptr->ident & ID_MAGIK)
  668.         (void) strcat(tmp_str, "magik ");
  669.       if (i_ptr->ident & ID_EMPTY)
  670.         (void) strcat(tmp_str, "empty ");
  671.       if (i_ptr->ident & ID_DAMD)
  672.         (void) strcat(tmp_str, "damned ");
  673.     }
  674.       if (i_ptr->inscrip[0] != '\0')
  675.     (void) strcat(tmp_str, i_ptr->inscrip);
  676.       else if ((indexx = strlen(tmp_str)) > 0)
  677.       /* remove the extra blank at the end */
  678.       tmp_str[indexx-1] = '\0';
  679.       if (tmp_str[0])
  680.     {
  681.       (void) sprintf(tmp_val, " {%s}", tmp_str);
  682.       (void) strcat(out_val, tmp_val);
  683.     }
  684.       (void) strcat(out_val, ".");
  685.     }
  686. }
  687.  
  688. void invcopy(to, from_index)
  689. register inven_type *to;
  690. int from_index;
  691. {
  692.   register treasure_type *from;
  693.  
  694.   from = &object_list[from_index];
  695.   to->index    = from_index;
  696.   to->name2     = SN_NULL;
  697.   to->inscrip[0] = '\0';
  698.   to->flags     = from->flags;
  699.   to->tval      = from->tval;
  700.   to->tchar     = from->tchar;
  701.   to->p1        = from->p1;
  702.   to->cost    = from->cost;
  703.   to->subval    = from->subval;
  704.   to->number    = from->number;
  705.   to->weight    = from->weight;
  706.   to->tohit     = from->tohit;
  707.   to->todam     = from->todam;
  708.   to->ac        = from->ac;
  709.   to->toac      = from->toac;
  710.   to->damage[0] = from->damage[0];
  711.   to->damage[1] = from->damage[1];
  712.   to->level     = from->level;
  713.   to->ident    = 0;
  714. }
  715.  
  716.  
  717. /* Describe number of remaining charges.        -RAK-    */
  718. void desc_charges(item_val)
  719. int item_val;
  720. {
  721.   register int rem_num;
  722.   vtype out_val;
  723.  
  724.   if (known2_p(&inventory[item_val]))
  725.     {
  726.       rem_num = inventory[item_val].p1;
  727.       (void) sprintf(out_val, "You have %d charges remaining.", rem_num);
  728.       msg_print(out_val);
  729.     }
  730. }
  731.  
  732.  
  733. /* Describe amount of item remaining.            -RAK-    */
  734. void desc_remain(item_val)
  735. int item_val;
  736. {
  737.   bigvtype out_val, tmp_str;
  738.   register inven_type *i_ptr;
  739.  
  740.   i_ptr = &inventory[item_val];
  741.   i_ptr->number--;
  742.   objdes(tmp_str, i_ptr, TRUE);
  743.   i_ptr->number++;
  744.   /* the string already has a dot at the end. */
  745.   (void) sprintf(out_val, "You have %s", tmp_str);
  746.   msg_print(out_val);
  747. }
  748.